package cDB

import (
	"reflect"
	"sync"

	"github.com/go-redis/redis/v8"
	"go.mongodb.org/mongo-driver/mongo"
	"gorm.io/gorm"

	"gitee.com/csingo/cDB/drivers"
)

type DBClient interface {
	*gorm.DB | *redis.Client | *mongo.Database
}

type DBContainer struct {
	lock       sync.RWMutex
	instances  map[string]any
	connectors map[string]drivers.ConnectorInterface
}

func (i *DBContainer) Save(instance any) bool {
	i.lock.Lock()
	defer i.lock.Unlock()

	index := instance.(drivers.ConnectorInterface).GetConnection()

	if _, ok1 := i.instances[index]; !ok1 {
		i.instances[index] = instance.(drivers.ConnectorInterface).GetDB()
	}
	if _, ok2 := i.connectors[index]; !ok2 {
		i.connectors[index] = instance.(drivers.ConnectorInterface)
	}

	return true
}

func (i *DBContainer) Get(name string) any {
	i.lock.RLock()
	defer i.lock.RUnlock()

	return i.instances[name]
}

func (i *DBContainer) Remove(name string) bool {
	i.lock.Lock()
	defer i.lock.Unlock()

	delete(i.instances, name)
	delete(i.connectors, name)

	return true
}

func (i *DBContainer) Is(instance any) bool {
	if instance == nil {
		return false
	}
	return reflect.TypeOf(instance).Implements(reflect.TypeOf((*drivers.ConnectorInterface)(nil)).Elem())
}

func (i *DBContainer) Range(f func(instance any)) {
	i.lock.RLock()
	defer i.lock.RUnlock()

	for _, item := range i.instances {
		f(item)
	}
}

func (i *DBContainer) Has(name string) bool {
	i.lock.RLock()
	defer i.lock.RUnlock()

	var exists bool
	_, exists = i.instances[name]
	if !exists {
		return exists
	}

	_, exists = i.connectors[name]

	return exists
}

func (i *DBContainer) GetConnector(name string) drivers.ConnectorInterface {
	i.lock.RLock()
	defer i.lock.RUnlock()

	return i.connectors[name]
}

var container = &DBContainer{
	lock:       sync.RWMutex{},
	instances:  make(map[string]any),
	connectors: make(map[string]drivers.ConnectorInterface),
}
